using System;
using System.Collections;
using System.ComponentModel;
using System.Security.Permissions;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

[assembly: WebResource("CodeStory.WebControls.Resource.TreeGrid_Expand.JPG", "image/jpg")]
[assembly: WebResource("CodeStory.WebControls.Resource.TreeGrid_Collapse.JPG", "image/jpg")]
[assembly: WebResource("CodeStory.WebControls.Resource.TreeGrid.js", "application/x-javascript")]
namespace CodeStory.WebControls
{
	[ToolboxData("<{0}:TreeGrid runat=server></{0}:TreeGrid>")]
	[AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
	[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
	[PersistChildren(false)]
	[ParseChildren(true)]
	public class TreeGrid : HierarchicalDataBoundControl, INamingContainer
	{
		private TreeNodeItem rootNodeItem;
		private bool _dataBound;
		private TreeGridColumnCollection columns;
		private TableItemStyle _rowStyle;

		private TreeGridRowCollection _rowsCollection;
		private ArrayList _rowsArray;

		internal TreeNodeItem RootNodeItem {
			get {
				if (rootNodeItem == null) {
					rootNodeItem = new TreeNodeItem(this, true);
					if (IsTrackingViewState) {
						((IStateManager)rootNodeItem).TrackViewState();
					}
				}
				return rootNodeItem;
			}
		}

		[DefaultValue("")]
		public string TreeNodeTextField {
			get {
				object obj = ViewState["TreeNodeTextField"];
				if (obj == null) {
					obj = ViewState["TreeNodeValueField"];
				}
				return obj == null ? string.Empty : (string)obj;
			}
			set { ViewState["TreeNodeTextField"] = value; }
		}

		[DefaultValue("")]
		public string TreeNodeValueField {
			get {
				object obj = ViewState["TreeNodeValueField"];
				if (obj == null) {
					obj = ViewState["TreeNodeTextField"];
				}
				return obj == null ? string.Empty : (string)obj;
			}
			set { ViewState["TreeNodeValueField"] = value; }
		}

		[DefaultValue(-1)]
		public int ExpandDepth {
			get {
				object obj = ViewState["ExpandDepth"];
				return obj == null ? -1 : (int)obj;
			}
			set { ViewState["ExpandDepth"] = value; }
		}

		[Browsable(true)]
		[PersistenceMode(PersistenceMode.InnerProperty)]
		public TreeGridColumnCollection Columns {
			get {
				if (columns == null) {
					columns = new TreeGridColumnCollection();
					if (IsTrackingViewState) {
						((IStateManager)columns).TrackViewState();
					}
				}
				return columns;
			}
		}
		[Category("Styles")]
		[PersistenceMode(PersistenceMode.InnerProperty)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
		[NotifyParentProperty(true)]
		public TableItemStyle RowStyle {
			get {
				if (this._rowStyle == null) {
					this._rowStyle = new TableItemStyle();
					if (base.IsTrackingViewState) {
						((IStateManager)this._rowStyle).TrackViewState();
					}
				}
				return this._rowStyle;
			}
		}

		[DefaultValue(10)]
		[Bindable(true)]
		[Category("Apperance")]
		public int ItemIndent {
			get {
				object obj = ViewState["ItemIndent"];
				return obj == null ? 10 : (int)obj;
			}
			set { ViewState["ItemIndent"] = value; }
		}

		[Category("Appearance")]
		[DefaultValue(GridLines.Both)]
		public virtual GridLines GridLines {
			get {
				if (!base.ControlStyleCreated) {
					return GridLines.Both;
				}
				return ((TableStyle)base.ControlStyle).GridLines;
			}
			set { ((TableStyle)base.ControlStyle).GridLines = value; }
		}

		[Bindable(true)]
		[Category("Apperance")]
		[Browsable(true)]
		public string CollapseImageUrl {
			get {
				object obj = ViewState["CollapseImageUrl"];
				if (obj == null) {
					return Page.ClientScript.GetWebResourceUrl(GetType(), "CodeStory.WebControls.Resource.TreeGrid_Collapse.JPG");
				}
				return (string)obj;
			}
			set { ViewState["CollapseImageUrl"] = value; }
		}
		[Bindable(true)]
		[Category("Apperance")]
		[Browsable(true)]
		public string ExpandImageUrl {
			get {
				object obj = ViewState["ExpandImageUrl"];
				if (obj == null) {
					return Page.ClientScript.GetWebResourceUrl(GetType(), "CodeStory.WebControls.Resource.TreeGrid_Expand.JPG");
				}
				return (string)obj;
			}
			set { ViewState["ExpandImageUrl"] = value; }
		}
		[Browsable(false)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
		public virtual TreeGridRowCollection Rows {
			get {
				if (this._rowsCollection == null) {
					if (this._rowsArray == null) {
						this.EnsureChildControls();
					}
					if (this._rowsArray == null) {
						this._rowsArray = new ArrayList();
					}
					this._rowsCollection = new TreeGridRowCollection(this._rowsArray);
				}
				return this._rowsCollection;
			}
		}

		public TreeNodeItemCollection NodeItems {
			get { return RootNodeItem.NodeItems; }
		}

		internal static string Escape(string value) {
			StringBuilder builder = null;
			if (string.IsNullOrEmpty(value)) {
				return string.Empty;
			}
			int startIndex = 0;
			int count = 0;
			for (int i = 0; i < value.Length; i++) {
				switch (value[i]) {
					case '\\':
						if (builder == null) {
							builder = new StringBuilder(value.Length + 5);
						}
						if (count > 0) {
							builder.Append(value, startIndex, count);
						}
						builder.Append("*|*");
						startIndex = i + 1;
						count = 0;
						break;
					case '|':
						if (builder == null) {
							builder = new StringBuilder(value.Length + 5);
						}
						if (count > 0) {
							builder.Append(value, startIndex, count);
						}
						builder.Append("||");
						startIndex = i + 1;
						count = 0;
						break;
					default:
						count++;
						break;
				}
			}
			if (builder == null) {
				return value;
			}
			if (count > 0) {
				builder.Append(value, startIndex, count);
			}
			return builder.ToString();
		}

		private void ExpandToDepth(TreeNodeItemCollection nodeItems, int depth) {
		}

		protected override void PerformDataBinding() {
			base.PerformDataBinding();
			//this.NodeItems.Clear();
			if ((!base.DesignMode && this._dataBound) && (string.IsNullOrEmpty(this.DataSourceID) && (this.DataSource == null))) {
				this.NodeItems.Clear();
			} else {
				this.DataBindNode(this.RootNodeItem);
				if (!string.IsNullOrEmpty(this.DataSourceID) || (this.DataSource != null)) {
					this._dataBound = true;
				}
				this.ExpandToDepth(this.NodeItems, this.ExpandDepth);
			}
			ClearChildViewState();
			CreateControlHierarchy(true);
		}

		private void DataBindNode(TreeNodeItem node) {
			if (TreeNodeTextField == string.Empty) {
				throw new ArgumentException("");
			}
			if ((node.PopulateOnDemand && !base.IsBoundUsingDataSourceID) && !base.DesignMode) {
				throw new InvalidOperationException("TreeView_PopulateOnlyForDataSourceControls");
			}
			HierarchicalDataSourceView data = this.GetData(node.DataPath);
			if (base.IsBoundUsingDataSourceID || (this.DataSource != null)) {
				if (data == null) {
					throw new InvalidOperationException("TreeView_DataSourceReturnedNullView");
				}
				IHierarchicalEnumerable enumerable = data.Select();
				node.NodeItems.Clear();
				if (enumerable != null) {
					this.DataBindRecursive(node, enumerable);
				}
			}
		}

		private void DataBindRecursive(TreeNodeItem nodeItem, IHierarchicalEnumerable enumerable) {
			int depth = nodeItem.Depth + 1;
			foreach (object item in enumerable) {
				IHierarchyData data = enumerable.GetHierarchyData(item);
				if (data != null) {
					TreeNodeItem node = new TreeNodeItem(this, false);
					nodeItem.NodeItems.Add(node);
					node.SetDataPath(data.Path);
					node.SetDataBind(true);

					SetTreeNodeProperty(node, data);

					node.SetDataItem(data.Item);
					//Raise node databind event
					//nodeItem.SetDataItem(null);
					if (data.HasChildren) {
						IHierarchicalEnumerable e = data.GetChildren();
						if (e != null) {
							DataBindRecursive(node, e);
						}
					}
				}
			}
		}

		private void SetTreeNodeProperty(TreeNodeItem node, IHierarchyData data) {
			object item = data.Item;
			node.Text = (string)DataBinder.GetPropertyValue(item, TreeNodeTextField);
			node.Value = (string)DataBinder.GetPropertyValue(item, TreeNodeValueField);
		}

		protected override void CreateChildControls() {
			//base.CreateChildControls();
			Controls.Clear();
			if (this.ViewState["_!ItemCount"] == null) {
				if (this.RequiresDataBinding) {
					this.EnsureDataBound();
				}
			} else {
				this.CreateControlHierarchy(false);
				base.ClearChildViewState();
			}
		}

		protected override void OnPreRender(EventArgs e) {
			Page.ClientScript.RegisterClientScriptResource(typeof(DataSourceHelper), "CodeStory.WebControls.Resource.CodeStory.js");
			Page.ClientScript.RegisterClientScriptResource(GetType(), "CodeStory.WebControls.Resource.TreeGrid.js");
			base.OnPreRender(e);
		}

		protected override void Render(HtmlTextWriter writer) {
			if (this.Page != null) {
				this.Page.VerifyRenderingInServerForm(this);
			}
			this.PrepareControlHierarchy();
			this.RenderContents(writer);
		}

		private void PrepareControlHierarchy() {
			if (Controls.Count == 0) {
				return;
			}
			TreeGridChildTable table = (TreeGridChildTable)this.Controls[0];
			table.CopyBaseAttributes(this);
			if (ControlStyleCreated && !ControlStyle.IsEmpty) {
				table.ApplyStyle(ControlStyle);
			} else {
				table.GridLines = GridLines.Both;
				table.CellSpacing = 0;
			}
		}

		private void CreateControlHierarchy(bool databound) {
			ChildControlsCreated = true;
			if (this._rowsArray != null) {
				this._rowsArray.Clear();
			} else {
				this._rowsArray = new ArrayList();
			}

			TreeGridChildTable table = new TreeGridChildTable(string.IsNullOrEmpty(this.ID) ? null : this.ClientID);
			Controls.Add(table);
			CreateTableRows(table.Rows, RootNodeItem, databound, 0);

			if (databound)
			ViewState["_!ItemCount"] = this._rowsArray == null ? -1 : this._rowsArray.Count;
		}

		private void CreateTableRows(TableRowCollection rows, TreeNodeItem nodeItem, bool databound, int index) {
			foreach (TreeNodeItem node in nodeItem.NodeItems) {
				TreeGridRow tgr = new TreeGridRow(node.DataItem, index, index);
				rows.Add(tgr);
				_rowsArray.Add(tgr);
				tgr.Depth = node.Depth;
				index++;
				tgr.ApplyStyle(RowStyle);
				CreateCellsForTableRow(tgr, node, databound);
				TreeGridEventArgs e = new TreeGridEventArgs(tgr);
				OnRowCreated(e);
				if (node.HasNodeItems) {
					tgr.HasChildRows = true;
					CreateTableRows(rows, node, databound, index);
				}
			}
		}

		private void CreateCellsForTableRow(TreeGridRow row, TreeNodeItem nodeItem, bool databound) {
			TreeGridCell c = new TreeGridCell();
			row.Cells.Add(c);
			c.Text = nodeItem.Text;
			c.ItemIndent = row.Depth * ItemIndent;
			foreach (TreeGridColumn col in Columns) {
				TreeGridCell tc = new TreeGridCell();
				row.Controls.Add(tc);
				tc.ApplyStyle(col.ItemStyle);
				col.BuildIn(tc, databound, row);
			}
			if (databound) {
				row.DataBind();
				OnRowDataBound(row);
			}
		}

		protected override Style CreateControlStyle() {
			TableStyle style = new TableStyle();
			style.GridLines = GridLines.Both;
			style.CellSpacing = 0;
			return style;
		}

		protected override bool OnBubbleEvent(object source, EventArgs args) {
			TreeGridCommandEventArgs e = args as TreeGridCommandEventArgs;
			if (e != null) {
				OnRowCommand(e);
			}
			return base.OnBubbleEvent(source, args);
		}

		#region ViewState
		protected override void TrackViewState() {
			base.TrackViewState();
			if (columns != null) {
				((IStateManager)columns).TrackViewState();
			}
			if (_rowStyle != null) {
				((IStateManager)_rowStyle).TrackViewState();
			}
			((IStateManager)NodeItems).TrackViewState();
		}

		protected override object SaveViewState() {
			object[] objArray = new object[4];
			objArray[0] = base.SaveViewState();
			bool flag = objArray[0] != null;
			if (columns != null) {
				objArray[1] = ((IStateManager)columns).SaveViewState();
				flag |= objArray[1] != null;
			}
			if (this._rowStyle != null) {
				objArray[2] = ((IStateManager)this.RowStyle).SaveViewState();
				flag |= objArray[2] != null;
			}
			objArray[3] = ((IStateManager)this.NodeItems).SaveViewState();
			if (flag | (objArray[3] != null)) {
				return objArray;
			}
			return null;
		}

		protected override void LoadViewState(object savedState) {
			if (savedState != null) {
				object[] objArray = (object[])savedState;
				if (objArray[0] != null) {
					base.LoadViewState(objArray[0]);
				}
				if (objArray[1] != null) {
					((IStateManager)this.Columns).LoadViewState(objArray[1]);
				}
				if (objArray[2] != null) {
					((IStateManager)this.RowStyle).LoadViewState(objArray[2]);
				}
				if (objArray[3] != null) {
					((IStateManager)this.NodeItems).LoadViewState(objArray[3]);
				}
			}
		}
		#endregion

		#region Events
		private static readonly object RowDataBoundEventObject = new object();
		public event TreeGridEventHandler RowDataBound {
			add { Events.AddHandler(RowDataBoundEventObject, value); }
			remove { Events.RemoveHandler(RowDataBoundEventObject, value); }
		}

		protected virtual void OnRowDataBound(TreeGridRow row) {
			TreeGridEventHandler handler = (TreeGridEventHandler)Events[RowDataBoundEventObject];
			if (handler != null) {
				TreeGridEventArgs e = new TreeGridEventArgs(row);
				handler(this, e);
			}
		}

		private static readonly object RowCommandEventObject = new object();
		public event TreeGridCommandEventHandler RowCommand {
			add { Events.AddHandler(RowCommandEventObject, value); }
			remove { Events.RemoveHandler(RowCommandEventObject, value); }
		}

		protected virtual void OnRowCommand(TreeGridCommandEventArgs e) {
			TreeGridCommandEventHandler handler = (TreeGridCommandEventHandler)Events[RowCommandEventObject];
			if (handler != null) {
				handler(this, e);
			}
		}
		private static readonly object RowCreatedEventObject = new object();
		public event TreeGridEventHandler RowCreated {
			add { Events.AddHandler(RowCreatedEventObject,value); }
			remove { Events.RemoveHandler(RowCreatedEventObject,value); }
		}
		protected virtual void OnRowCreated(TreeGridEventArgs e) {
			TreeGridEventHandler handler = (TreeGridEventHandler)Events[RowCreatedEventObject];
			if (handler != null) {
				handler(this,e);
			}
		}
		#endregion

		public TreeNodeItem CreateNode() {
			return new TreeNodeItem(this, false);
		}
	}
}